#include "LedDriver.h"
#include "RuntimeError.h"

static uint16_t * ledsAddress;
static uint16_t ledsImage;

enum{ ALL_LEDS_ON = ~0,	ALL_LEDS_OFF = ~ALL_LEDS_ON };
enum{ FIRST_LED = 1, LAST_LED = 16 };

uint16_t convertLedNumberToBit( int ledNumber )
{
	return 1 << ( ledNumber - 1 );
}

void updateHardware( void )
{
	*ledsAddress = ledsImage;
}

static BOOL IsLedOutOfBounds( int ledNumber )
{
	BOOL isLedOutOfBounds = ( ledNumber < FIRST_LED ) || (ledNumber > LAST_LED );
	if( isLedOutOfBounds )
		RUNTIME_ERROR( "LED Driver: out-of-bounds LED", -1 );

	return isLedOutOfBounds;
}

static void setLedImageBit( int ledNumber )
{
	ledsImage |= convertLedNumberToBit( ledNumber );
}

static void clearLedImageBit( int ledNumber )
{
	ledsImage &= ~( convertLedNumberToBit( ledNumber ) );
}

void LedDriver_Create(uint16_t * address)
{
	ledsAddress = address;
	ledsImage = ALL_LEDS_OFF;
	*address = ledsImage;
}

void LedDriver_Destroy(void)
{
}

void LedDriver_TurnOn(int ledNumber)
{
	if( IsLedOutOfBounds( ledNumber ) )
		return;

	setLedImageBit( ledNumber );
	updateHardware();
}

BOOL LedDriver_IsOn( int ledNumber )
{
	if( IsLedOutOfBounds( ledNumber ) )
		return FALSE;

	return ledsImage & ( convertLedNumberToBit( ledNumber ) );
}

BOOL LedDriver_IsOff( int ledNumber )
{
	return !LedDriver_IsOn( ledNumber );
}

void LedDriver_TurnOff(int ledNumber)
{
	if( IsLedOutOfBounds( ledNumber ) )
			return;

	clearLedImageBit( ledNumber );
	updateHardware();
}

void LedDriver_TurnAllOn( void )
{
	ledsImage = ALL_LEDS_ON;
	updateHardware();
}

void LedDriver_TurnAllOff( void )
{
	ledsImage = ALL_LEDS_OFF;
	updateHardware();
}
